#include "TcpConnection.h"
#include "InetAddress.h"
#include "Channel.h"
#include "Logger.h"

static EventLoop *checkLoopNotNull(EventLoop *loop)
{
    if (loop == nullptr)
    {
        LOG_FATAL("tcpserver loop is null");
    }
    return loop;
}

TcpConnection::TcpConnection(EventLoop *loop, const std::string &name, int sockfd, const InetAddress &localAddr, const InetAddress &perAddr)
    : loop_(checkLoopNotNull(loop)), name_(name), state_(StateE::kConnecting), reading_(true), socket_(new Socket(sockfd)), channel_(new Channel(loop, sockfd)), localAddr_(localAddr), peerAddr_(perAddr), highWaterMark_(64 * 1024 * 1024)
{
    channel_->setReadCallback(std::bind(&TcpConnection::handleRead, this, std::placeholders::_1));
    channel_->setWriteCallback(std::bind(&TcpConnection::handleWrite, this));
    channel_->setCloseCallback(std::bind(&TcpConnection::handleClose, this));
    channel_->setErrorCallback(std::bind(&TcpConnection::handleError, this));

    socket_->setKeepAlive(true);
}
TcpConnection::~TcpConnection() { /* 自动析构 */ }
// send
void TcpConnection::send(const std::string &buff)
{
    if (state_ != kConnected)
    {
        LOG_ERROR("send error, state_ != connected");
        return;
    }

    if (loop_->isInLoopThread())
    {
        sendInLoop(buff.c_str(), buff.size());
    }
    else
    {
        loop_->runInLoop(std::bind(&TcpConnection::sendInLoop, this, buff.c_str(), buff.size()));
    }
}
// shutdown
void TcpConnection::shutdown()
{
    if (state_ == kConnected)
    {
        setState(StateE::kDisconnecting);
        loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this));
    }
    
}
// 建立
void TcpConnection::connectEstablished()
{
    LOG_INFO("connectEstablished start, connection");
    setState(StateE::kConnected);
    channel_->tie(shared_from_this());
    channel_->enableReading();

    // 执行回调
    connectionCallback_(shared_from_this());
}
// 销毁
void TcpConnection::connectDestroyed()
{
    if(state_ == StateE::kConnected){
        setState(StateE::kDisconnected);
        channel_->disableAll();
        connectionCallback_(shared_from_this());
    }
    channel_->remove();  //将channel从epollpoller中删掉
}

void TcpConnection::handleRead(Timestamp receiveTime)
{
    LOG_INFO("handlerread start");
    int saveErrno = 0;
    ssize_t n = inputBuffer_.readFd(channel_->fd(), &saveErrno);
    LOG_INFO("read size n = %d", (int)n);
    if (n > 0)
    {
        // 有可读事件发生，调用用户的回调
        messageCallback_(shared_from_this(), inputBuffer_, receiveTime);
    }
    else if (n == 0)
    {
        handleClose();
    }
    else
    {
        LOG_ERROR("handle read error n < 0");
        handleError();
    }
}

void TcpConnection::handleWrite()
{
    if (channel_->isWriting())
    {
        int saveErrno = 0;
        ssize_t n = outputBuffer_.writeFd(channel_->fd(), &saveErrno);
        if (n > 0)
        {
            outputBuffer_.retrieve(n);

            if (outputBuffer_.readableBytes() == 0)
            {
                channel_->disableWriting();
                if (writeCompleteCallback_)
                {
                    loop_->runInLoop(std::bind(writeCompleteCallback_, shared_from_this()));
                }

                if (state_ == kDisconnecting)
                {
                    shutdownInLoop();
                }
            } // 如果还有空间不做额外处理
        }
        else
        {
            // n = 0, 如果小于0前面会fatal
            LOG_ERROR("hanle write error, n = 0");
        }
    }
    else
    {
        LOG_ERROR("handle write error");
    }
}

void TcpConnection::handleClose()
{
    setState(StateE::kDisconnected);
    channel_->disableAll();

    TcpConnectionPtr ptr(shared_from_this());
    connectionCallback_(ptr);
    closeCallback_(ptr);
}

void TcpConnection::handleError()
{
    int optval;
    socklen_t optlen = sizeof(optval);
    int err = 0;
    if (::getsockopt(channel_->fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
    {
        LOG_ERROR("handle error");
    }
}

void TcpConnection::sendInLoop(const void *data, size_t len)
{
    // 已经写了多少
    ssize_t nwrote = 0;
    // 没写完数量
    size_t remaining = 0;
    bool faultError = false;
    if (state_ == kDisconnected)
    {
        LOG_ERROR("send error, state_ != connected");
        return;
    }

    // 能直接发送就直接发送，
    // 不能全部发送则将剩余部分放入缓冲区，等待 socket 可写时再继续发送
    // 写完后关闭写事件
    if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) // 第一次写且缓冲区无数据
    {
        nwrote = ::write(channel_->fd(), data, len);
        if (nwrote >= 0)
        {
            remaining = len - nwrote;
            if (remaining == 0 && writeCompleteCallback_) // 写完了
            {
                // 将写事件关掉
                loop_->runInLoop(std::bind(writeCompleteCallback_, shared_from_this()));
            }
        }
    }

    if (!faultError && remaining > 0) // 没发生异常，但是没有发完， ramaining 只可能>=0
    {
        size_t oldLen = outputBuffer_.readableBytes();
        if (oldLen + remaining >= highWaterMark_ &&
            oldLen < highWaterMark_ &&
            highWaterMarkCallback_)
        {
            loop_->runInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining));
        }

        outputBuffer_.append((char *)data + nwrote, remaining);
        if (!channel_->isWriting())
        {
            channel_->enableWriting();
        }
    }
}

void TcpConnection::shutdownInLoop()
{
    if(!channel_ -> isWriting()){
        socket_->shutdownWrite();
    }
}
